/*
 * LogEx a Java library for extracting log file data
 * Copyright 2012 LogEx Team.
 *
 * This program is free software. You can distribute or modify it under the 
 * terms of the GNU Lesser General Public License version 3.0 as published by  
 * the Free Software Foundation.
 *
 * This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
 * INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, contact the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package org.basex.api;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.xquery.XQDataSource;
import javax.xml.xquery.XQConnection;
import javax.xml.xquery.XQExpression;
import javax.xml.xquery.XQResultSequence;
import javax.xml.xquery.XQException;

import org.logex.main.StringConstants;


import net.xqj.basex.BaseXXQDataSource;

public class DatabaseHandler {
	
	private String serverName = null;
	private String port = null;
	private String user = null;
	private String password = null;
	private String dataBase = null;
	private DatabaseSettings dbSettings = null;
	private static final String SERVER_NAME = "serverName";
	private static final String PORT = "port";
	private static final String USER = "user";
	private static final String PASSWORD = "password";
	private static final String FILE_NAME = "Results";

	public DatabaseHandler() throws FileNotFoundException, IOException,
			XQException {
		this.dbSettings = new DatabaseSettings();
		this.serverName = dbSettings.getDatabaseServer();
		this.port = dbSettings.getPort();
		this.user = dbSettings.getUserName();
		this.password = dbSettings.getPassword();
		this.dataBase = dbSettings.getDatabaseName();
		this.createXMLDatabase();
	
	}

	/**
	 * Creates an XML database.
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 */
	private void createXMLDatabase() throws XQException {
		XQConnection xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		xqe.executeCommand("CHECK " + dataBase);
		xqc.close();
	}

	/**
	 * Creates a connection with an existing XML database.
	 * 
	 * @param serverName
	 *            The name of the database server
	 * @param port
	 *            The port of the database server which listens to connections
	 * @param user
	 *            The user name for connecting to the database
	 * @param password
	 *            The password for connecting to the database
	 * 
	 * @return a connection to the database server
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 */
	private XQConnection createConnection(String serverName, String port,
			String user, String password) throws XQException {
		XQDataSource ds = new BaseXXQDataSource();
		ds.setProperty(SERVER_NAME, serverName);
		ds.setProperty(PORT, port);
		ds.setProperty(USER, user);
		ds.setProperty(PASSWORD, password);
		return ds.getConnection();
	}

	/**
	 * Add a file to the database.
	 * 
	 * @param file
	 *            The name of the file to be added
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 */
	public void addFile(String file) throws XQException {
		XQConnection xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		xqe.executeCommand("CHECK " + dataBase);
		xqe.executeCommand("ADD " + System.getProperty("user.dir")
				+ File.separator + file);
		xqc.close();

	}

	/**
	 * Method for custom queries over the database
	 * 
	 * @param query
	 *            The query to run over the database
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 * @throws IOException
	 */
	public void queryXML(String query, String outputFile) throws XQException,
			IOException {
		XQConnection xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		XQResultSequence rs = xqe.executeQuery(query);
		BufferedWriter out = new BufferedWriter(new FileWriter(
				System.getProperty("user.dir") + File.separator + FILE_NAME
						+ File.separator + outputFile));
		out.write(StringConstants.LOG_FILE_START_TAG);
		rs.writeSequence(out, null);
		out.write(StringConstants.LOG_FILE_END_TAG);
		out.flush();
		out.close();
	}

	/**
	 * Reads the given xml file in the database
	 * 
	 * @param filename
	 *            The name of the file to be read from the database
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 * @throws FileNotFoundException
	 *             If a file cannot be created
	 */
	public void readXMLFile(String fileName) throws XQException,
			FileNotFoundException {
		XQConnection xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		XQResultSequence rs = xqe.executeQuery("for $x in collection('"
				+ dataBase + "/" + fileName + "') return $x");

		rs.writeSequence(new FileOutputStream(System.getProperty("user.dir")
				+ File.separator + FILE_NAME + File.separator + fileName), null);
	}

	/**
	 * Updates an existing xml file in the database.
	 * 
	 * @param fileName
	 *            The existing xml file to be updated
	 * @param nodes
	 *            The nodes to be added
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 */
	public void updateFile(String fileName, String nodes) throws XQException {
		XQConnection xqc;
		xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		xqe.executeCommand("OPEN " + dataBase);
		xqe.executeCommand("XQUERY insert node" + nodes + " into collection('"
				+ dataBase + "/" + fileName + "')/Log");

	}

	/**
	 * Get the names of the documents of the data base.
	 * 
	 * @return document names
	 * 
	 * @throws XQException
	 *             If a connection cannot be made with the database server
	 */
	public ArrayList<String> getDocumentNames() throws XQException {
		ArrayList<String> documents = new ArrayList<String>();
		XQConnection xqc;
		xqc = createConnection(serverName, port, user, password);
		XQExpression xqe = xqc.createExpression();
		xqe.executeCommand("OPEN " + dataBase);
		XQResultSequence rs = xqe.executeQuery("for $x in collection('"
				+ dataBase + "') return fn:document-uri($x) ");
		while (rs.next()) {
			documents.add(rs.getItemAsString(null));
		}
		return documents;

	}

}
